import sys
import os
import json
import time
from simple_chalk import chalk
import argparse
from argparse import ArgumentParser
from PyInquirer import prompt
import re

class SmartFormatter(argparse.HelpFormatter):
    def _split_lines(self, text, width):
        if text.startswith('R|'):
            return text[2:].splitlines()
        return argparse.HelpFormatter._split_lines(self, text, width)

# for chalk works
os.system("")


def pickToFirst(ls, val):
    if val in ls:
        ls.remove(val)
    ls.insert(0, val)

    return ls


def headStr(hd="", w=5, c=" "):
    if w is None:
        w = 5
    if c is None:
        c = " "
    return hd.rjust(w, c) + " "


def percentStr(start, end):
    return "%s/%s" % (start, end)


# 输出1行信息，包含标头和内容
def headLog(msg, head="", w=None, c=None, color=None):
    con = headStr(head, w, c) + msg
    if color:
        print(getattr(chalk, color)(con))
    else:
        print(con)


def headLogSuc(*args, **kw):
    if not 4 in range(len(args)):
        kw.setdefault("color", "green")
    return headLog(*args, **kw)


def headLogInfo(*args, **kw):
    if not 4 in range(len(args)):
        kw.setdefault("color", "cyan")
    return headLog(*args, **kw)


def headLogWarn(*args, **kw):
    # print(args, kw, "<----------")
    if not 4 in range(len(args)):
        kw.setdefault("color", "yellow")
    return headLog(*args, **kw)


def headLogErr(*args, **kw):
    if not 4 in range(len(args)):
        kw.setdefault("color", "red")
    return headLog(*args, **kw)


def savePassResultToFile(user, book, dailyFile, isTest, config):
    resultFile = config["resultFile"]
    absResultFile = getAbsPath(resultFile, config)
    data = {}
    if os.path.exists(absResultFile):
        with open(absResultFile, "r", encoding="utf8") as f:
            data = json.load(f)

    data["lastUser"] = user
    data[user] = {
        "user": user,
        "book": book,
        "dailyFile": dailyFile,
        "date": str(time.strftime("%Y-%m-%d %H:%M:%S")),
        "isTest": isTest,
    }
    with open(absResultFile, "w", encoding="utf8") as f:
        json.dump(data, f)

    return True


def getLastResult(config):
    lastResult = {}
    absResultFile = getAbsPath(config["resultFile"], config)
    if os.path.exists(absResultFile):
        with open(absResultFile, "r", encoding="utf8") as f:
            lastResult = json.load(f)

    return lastResult


def getAbsPath(p, config):
    appDir = config.get("appDir")
    return os.path.abspath(os.path.join(__file__, r"../../%s/%s" % (appDir, p)))


def getAbsPathOfDailyFile(fileName, config):
    absDailyDir = getAbsPath(config["dailyDir"], config)
    return os.path.abspath(os.path.join(absDailyDir, fileName))


def getBooks(config):
    absBookDir = getAbsPath(config["bookDir"], config)
    return [dir.partition(".")[0] for dir in os.listdir(absBookDir)]


def getAllDailyFiles(config):
    absDailyDir = getAbsPath(config["dailyDir"], config)
    return os.listdir(absDailyDir)


def getDailyFilesOfBook(book, config):
    files = getAllDailyFiles(config)
    return [fname for fname in files if fname.startswith(book)]


def getMaxSnOfBook(book, config):
    files = getDailyFilesOfBook(book, config)
    if not len(files):
        return 0
    return max([int(val.replace(book, "").replace(".txt", "")) for val in files])

def getMinSnOfBook(book, config):
    files = getDailyFilesOfBook(book, config)
    if not len(files):
        return 0
    return min([int(val.replace(book, "").replace(".txt", "")) for val in files])


def getFileName(book, sn):
    return book + str(sn).rjust(4, "0") + ".txt"


def getBookContent(book, config):
    absBookPath = getAbsPath("%s/%s.txt" % (config.get("bookDir"), book), config)
    shortBookPath = absBookPath.replace(
        os.path.abspath(os.path.join(absBookPath, "../..")), ""
    )
    if not os.path.exists(absBookPath):
        print("合集文件 %s 不存在, 请检查输入" % shortBookPath)
        sys.exit(1)

    lines = []
    with open(absBookPath, "r", encoding="utf8") as f:
        lines = f.readlines()

    # 双横线行后面的内容才是需要处理的
    dblDashLineIndexLs = [
        index
        for index, line in enumerate(lines)
        if line.startswith(config.get("newContentLineMark"))
    ]
    if len(dblDashLineIndexLs):
        lastIndex = dblDashLineIndexLs.pop()
        lines = lines[lastIndex + 1 :]

    return lines


def getDailyFileContent(book, sn, config):
    fname = getFileName(book, sn)
    absFileName = getAbsPath("%s/%s" % (config["dailyDir"], fname), config)
    lines = []

    if not os.path.exists(absFileName):
        dirPath = os.path.abspath(os.path.join(absFileName, "../.."))
        shortFilePath = absFileName.replace(dirPath, "")
        print("文件 %s 不存在, 请检查输入" % shortFilePath)
        sys.exit(1)

    with open(absFileName, "r", encoding="utf8") as f:
        lines = f.readlines()

    return lines


def getFileNameByNum(isNumArg):
    numStr = sys.argv[1]
    numLs = list(numStr)
    alphaLs = [v for v in numLs if not v.isdecimal()]

    if isNumArg and len(alphaLs):
        print("参数不是全数字")
        return False

    numLs.insert(2, "U")
    fname = "phrase%s.txt" % "".join(numLs)

    return fname


def toGroups(ls, size=3):
    appendingTime = 1
    groups = []
    newGroup = []
    for i, v in enumerate(ls):
        if appendingTime > size:
            groups.append(newGroup)
            appendingTime = 1
            newGroup = []

        newGroup.append(v)
        appendingTime += 1
        if i == len(ls) - 1:
            groups.append(newGroup)

    return groups


def departToPhrases(lines):
    parts = []
    start = None
    end = None
    for index, line in enumerate(lines):
        line = line.strip()
        if line == "":
            # 开始空行都跳过
            if start is None:
                continue

            # 首次遇到空行，更新end
            if end is None:
                end = index
                parts.append(lines[start:end])
                start = None
        else:
            # 首次遇到非空行，更新start
            if start is None:
                start = index
                end = None

        # 末尾
        if index == len(lines) - 1:
            # 末尾为非空行
            if end is None:
                end = len(lines)
                parts.append(lines[start:end])

    return parts


def createDailyFile(phraseList, index, book, config):
    sn = index + 1
    fileName = getFileName(book, sn)
    absFilePath = getAbsPath("%s/%s" % (config.get("dailyDir"), fileName), config)

    phraseLs = ["".join(phrase) for phrase in phraseList]
    phraseCon = "\n".join(phraseLs)

    with open(absFilePath, "w", encoding="utf8") as f:
        f.write(phraseCon)

    print("write file ok:", absFilePath)


def createBookDailyFiles(book, config):
    lines = getBookContent(book, config)
    phraseList = departToPhrases(lines)
    groupList = toGroups(phraseList, config.get("dailyCount"))
    for index, group in enumerate(groupList):
        createDailyFile(group, index, book, config)

    print()
    print(chalk.yellow("短语集合 %s 已成功生成对应短语文件" % book))

    return True

lessonsCount = 0
def getFileCount(answer, questions, config):
    global lessonsCount
    lessonsCount = getMaxSnOfBook(answer.get('book'), config)
    minSn = getMinSnOfBook(answer.get('book'), config)
    pat = re.compile(r':')
    suffix = ('[%d-%d]' % (minSn, lessonsCount)) + ': '
    questions[2]["message"] = pat.sub( suffix, questions[2]["message"])
    return False

def getArgsByQuestions(lastResult, config, type):
    global lessonsCount
    # !!! 颜色转义序列在 window 下不生效, 需要 help(os.path), 或执行类似下面
    # 非常玄学
    os.system("")

    # global args
    args = {}

    lastUser = lastResult.get("lastUser")
    userQuestion = [
        {
            "type": "input",
            "name": "user",
            "message": "你的昵称是:",
            "default": lastUser or "",
        }
    ]

    userAnswer = prompt(userQuestion)

    if not userAnswer.get("user"):
        print("\n开始前, 请先输入你的昵称 :)")
        sys.exit(1)

    userLastResult = lastResult.get(userAnswer.get("user")) or {}
    lastUser = userLastResult.get("user")
    lastDate = userLastResult.get("date")
    lastIsTest = userLastResult.get("isTest")
    lastBook = userLastResult.get("book")
    lastDailyFile = userLastResult.get("dailyFile")
    lastSn = ""

    if lastUser:
        print()
        print(
            chalk.cyan(
                "欢迎回来 %s! \n你上次在 %s %s通过%s <%s/%s>"
                % (
                    lastUser,
                    lastDate,
                    "测试" if lastIsTest else "练习",
                    type,
                    lastBook,
                    lastDailyFile,
                )
            )
        )
        print()

    books = getBooks(config)

    if lastDailyFile:
        lastSn = int(lastDailyFile.strip(lastBook).rstrip(".txt"))
        lastSn = str(lastSn)

    if lastBook:
        pickToFirst(books, lastBook)

    questions = [
        {"type": "list", "name": "book", "message": "选择%s册子:" % type, "choices": books},
        {"type": "input", "name": "fileCount", "message": "do not need msg", "when": lambda answer: getFileCount(answer, questions, config) },
        {
            "type": "input",
            "name": "dailyFileSn",
            "message": "%s文件序号: " % (type,),
            "default": lastSn or "1",
        },
    ]

    args = prompt(questions)
    args["user"] = userAnswer.get("user")
    args["dailyFile"] = getFileName(
        args.get("book") or "book", args.get("dailyFileSn") or 1
    )

    print()
    if not args["dailyFile"]:
        print("输入有误，请输入%s文件序号" % type)
        sys.exit(1)

    if not args["dailyFileSn"].isdecimal():
        print("输入有误，%s文件序号应该为整数" % type)
        sys.exit(1)

    print()
    testAnswer = input(chalk.magenta("要现在开始测试吗?(y/N) "))
    isTest = False
    if testAnswer:
        isTest = testAnswer.lower() == "y"

    print()
    print(chalk.cyan("%s测试开始..." % type if isTest else "开始练习模式..."))
    print()

    args["isTest"] = isTest

    # print(args, "<---")
    return args


def getCliArgs(type):
    # global cargs
    cmd = "ptest" if type == "短语" else "wtest"
    print('\n')
    parser = ArgumentParser(cmd, "%s <action> -b <name> -c" % cmd, "%s练习和测试程序" % type, formatter_class=SmartFormatter)
    parser.add_argument(
        "action",
        type=str,
        help="R|需要执行的操作，目前只支持3种action \n- create(从单词本pet.txt取最新单词创建为新单词文件) %s" % ("" if cmd == "ptest" else " \n- yinbiao(为创建的新单词文件添加音标) \n- daily(自动完成所有操作：temp.txt -> pet.txt -> pet00XX.txt -> yinbiao) "),
    )
    parser.add_argument("-b", "--book", required=True, help="需要处理的%s合集" % type)
    parser.add_argument(
        "-c", "--clear", action="store_true", help="是否先删除短语合集现有的%s文件?" % type
    )

    cargs = parser.parse_args()

    return cargs


def lineLog(msg, w=60):
    print("-" * 30)
    print(msg)
    print("-" * 30)


def getNow():
    return time.strftime("%Y-%m-%d %H:%M:%S")
